#include "QFaceClipper.h"
#include <glm/gtx/transform.hpp>
#include <QGLWidget>

#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE  0x809D
#endif

static QGLWidget *_pFakeWidget = NULL;

QFaceClipper::QFaceClipper () : _pGLContext (NULL)
{
	_pFakeWidget = new QGLWidget ();
	_pFakeWidget->showMinimized ();
	_pFakeWidget->hide ();
	_pGLContext = new QGLContext (
			QGLFormat (QGL::SingleBuffer | QGL::DepthBuffer));
	_pGLContext->create ();
	_pGLContext->makeCurrent ();
	QGLFramebufferObjectFormat frameBufferFormat;
	frameBufferFormat.setInternalTextureFormat (GL_RGB);
	_pFaceFrameBufObj = new QGLFramebufferObject (140, 150, frameBufferFormat);
}

QFaceClipper::~QFaceClipper ()
{
	delete _pFakeWidget;
	delete _pGLContext;
	delete _pFaceFrameBufObj;
	_pFakeWidget = NULL;
	_pGLContext = NULL;
	_pFaceFrameBufObj = NULL;
}

QImage QFaceClipper::clipFace (Model &model)
{
	_saveGLState ();
	glClearColor (0, 0, 0, 1);
	glEnable (GL_COLOR_MATERIAL);
	glEnable (GL_DEPTH_TEST);
	//glEnable (GL_CULL_FACE);
	glShadeModel (GL_SMOOTH);
	glEnable (GL_MULTISAMPLE);
	glEnable (GL_TEXTURE_2D);
	//glPolygonMode(GL_FRONT_AND_BACK   ,GL_LINE   );

	_pGLContext->makeCurrent ();
	int width = _pFaceFrameBufObj->width ();
	int height = _pFaceFrameBufObj->height ();
	glViewport (0, 0, width, height);
	glMatrixMode (GL_PROJECTION);
	glLoadMatrixd (&glm::ortho (-0.5 / height * width, 0.5 / height * width,
			-0.5, 0.5, 0.1, 40.0)[0][0]);
	glMatrixMode (GL_MODELVIEW);
	glLoadIdentity ();
	glTranslatef (0.0f, 0.0f, -10.0f);

	_pFaceFrameBufObj->bind ();
	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	if (model.vertices.size () &&
			model.vertices.size () == model.texCoords.size () &&
			model.indices.size ()) {
		GLuint texId = -1;
		if (!model.texture.isNull ())
			texId = _pGLContext->bindTexture (model.texture,
			GL_TEXTURE_2D, GL_RGBA,
			QGLContext::LinearFilteringBindOption);
		glEnableClientState (GL_VERTEX_ARRAY);
		glEnableClientState (GL_TEXTURE_COORD_ARRAY);
		glEnableClientState (GL_VERTEX_ARRAY);
		glVertexPointer (3, GL_FLOAT, 0, &model.vertices[0]);
		glTexCoordPointer (2, GL_FLOAT, 0, &model.texCoords[0]);
		glDrawElements (GL_TRIANGLES, model.indices.size () * 3,
			GL_UNSIGNED_INT, &model.indices[0]);
		glDisableClientState (GL_VERTEX_ARRAY);
		glDisableClientState (GL_TEXTURE_COORD_ARRAY);
		glDisableClientState (GL_VERTEX_ARRAY);
		_pGLContext->deleteTexture (texId);
	}
	_pFaceFrameBufObj->release ();

	_restoreGLState ();
	return _pFaceFrameBufObj->toImage ();
}

void QFaceClipper::_saveGLState ()
{
	glPushAttrib (GL_ALL_ATTRIB_BITS);
	glMatrixMode (GL_PROJECTION);
	glPushMatrix ();
	glMatrixMode (GL_MODELVIEW);
	glPushMatrix ();
}

void QFaceClipper::_restoreGLState ()
{
	glMatrixMode (GL_PROJECTION);
	glPopMatrix ();
	glMatrixMode (GL_MODELVIEW);
	glPopMatrix ();
	glPopAttrib ();
}
